package cn.fighter3.controller;

import cn.fighter3.dto.SubjectPageDTO;
import cn.fighter3.entity.SubjectBook;
import cn.fighter3.entity.SubjectBookWord;
import cn.fighter3.entity.SubjectWord;
import cn.fighter3.mapper.SubjectBookMapper;
import cn.fighter3.mapper.SubjectBookWordMapper;
import cn.fighter3.mapper.SubjectWordMapper;
import cn.fighter3.result.Result;
import cn.fighter3.service.SubjectBookService;
import cn.fighter3.service.SubjectBookWordService;
import cn.fighter3.service.SubjectWordService;
import cn.fighter3.vo.BookTotalVo;
import cn.fighter3.vo.SubVO;
import cn.fighter3.vo.SubjectVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.stream.Stream;

@Controller
public class SubjectController {

    @Value("${subjectFile.location}")
    String path;

    @Value("${corpusFile.location}")
    String corpusFileName;

    @Value("${wordFile.location}")
    String wordFileName;

    @Autowired
    SubjectBookMapper subjectBookMapper;

    @Autowired
    SubjectWordMapper subjectWordMapper;

    @Autowired
    SubjectBookWordMapper subjectBookWordMapper;

    @Autowired
    SubjectBookService sbService;

    @Autowired
    SubjectWordService swService;

    @Autowired
    SubjectBookWordService sbwService;

    @PostMapping("/api/upload")
    @ResponseBody
    public Result upFile(@RequestParam("file") MultipartFile file, Map map) {
        System.out.println("收到文件");

        String fileName = file.getOriginalFilename();//获取文件名称
        String suffixName=fileName.substring(fileName.lastIndexOf("."));//获取文件后缀
//        fileName= UUID.randomUUID()+suffixName;//重新生成文件名
        System.out.println(fileName);
        System.out.println("type::" + suffixName);
        System.out.println("filename::" + fileName);
        File targetFile = new File(path);
        if (!targetFile.exists()) {
            // 判断文件夹是否未空，空则创建
            targetFile.mkdirs();
        }
        File saveFile = new File(targetFile, "external.txt");
        try {
            //指定本地存入路径
            file.transferTo(saveFile);
            System.out.println("执行成功");
            String path1 = path + fileName;
            System.out.println(path1);
            //     return "success";
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("执行失败");
            return new Result(200, "failed", null);
        }

        return new Result(200, "success", fileName);
    }

    @GetMapping("/api/train")
    @ResponseBody
    public Result startTrain() throws InterruptedException, IOException {

        //即使发生异常，后续程序也会往下执行
        int r = completeTrain();

        if (r==0){
            //保存结果
            saveSubject();
            saveWords();

            //查询结果返回给前端

            return new Result(200, "success", null);
        }
        return new Result(200, "failed", null);

    }


    public int completeTrain() throws IOException {
        Process proc;
        try {

           // proc = Runtime.getRuntime().exec("cmd /C start F:\\KG\\run.bat");// 执行py文件

            String[] args1 = new String[]{"D:\\anaconda\\Anaconda\\python","F:\\mypython\\final_subject\\bbdw\\main.py"};
            proc = Runtime.getRuntime().exec(args1);

            //用输入输出流来截取结果
            BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            String line = null;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
            in.close();
            //返回0调用成功，返回1调用失败
            return proc.waitFor();

        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 0;
    }

    public void saveSubject() throws IOException {

        List<SubjectBook> bookList = new ArrayList<>();
        int id = 0;
        // 转换成List<String>, 要注意java.lang.OutOfMemoryError: Java heap space
        List<String> lines = Files.readAllLines(Paths.get(corpusFileName),
                StandardCharsets.UTF_8);

        for(String line: lines){

            String title = line.split("\t")[0];

            SubjectBook sb = new SubjectBook();
            sb.setBookId(id);
            sb.setBookName(title);
            bookList.add(sb);
            id++;
        }
        sbService.saveBatch(bookList);
        System.out.println("保存书本成功");
    }


    public void saveWords() throws IOException {
        int index = 0;
        int id = 0;
        List<SubjectWord> wordList = new ArrayList<>();
        List<SubjectBookWord> bwList = new ArrayList<>();
        HashMap<String, Integer> map = new HashMap<>();

        // 转换成List<String>, 要注意java.lang.OutOfMemoryError: Java heap space
        List<String> lines = Files.readAllLines(Paths.get(wordFileName),
                StandardCharsets.UTF_8);
        for(String line: lines){
            String[] words = line.split(" ");
            for(String word: words){
                if (!map.containsKey(word)){
                    SubjectWord sw = new SubjectWord(id, word);
                    wordList.add(sw);
                    map.put(word, id);
                    SubjectBookWord sbw = new SubjectBookWord(index, id);
                    bwList.add(sbw);
                    id++;
                }else{
                    SubjectBookWord sbw = new SubjectBookWord(index, map.get(word));
                    bwList.add(sbw);
                }
            }
            index++;
        }
        swService.saveBatch(wordList);
        System.out.println("主题词保存完成");
        sbwService.saveBatch(bwList);
        System.out.println("文本-主题词关系保存成功");
    }


    @GetMapping("/api/subjectData")
    @ResponseBody
    public Result findSubjectData(){
        List<SubjectBook> bookList = subjectBookMapper.selectList(null);
        List<SubjectWord> wordsList = subjectWordMapper.selectList(null);
        List<SubjectBookWord> bookWordList = subjectBookWordMapper.selectList(null);

        int index = 0;
        HashMap<Integer, Integer> bookMap = new HashMap<>();
        HashMap<Integer, Integer> wordMap = new HashMap<>();
        for(SubjectBook book: bookList){
            bookMap.put(book.getBookId(), index);
            index++;
        }
        for(SubjectWord word: wordsList){
            wordMap.put(word.getWordId(), index);
            index++;
        }

        List<List<Integer>> edgeList = new ArrayList<>();
        for(SubjectBookWord bookWord: bookWordList){
            List<Integer> temp = new ArrayList<>();
            int bookId = bookWord.getBookId();
            int wordId = bookWord.getWordId();
            temp.add(bookMap.get(bookId));
            temp.add(wordMap.get(wordId));
            edgeList.add(temp);
        }

        List<Object> node = new ArrayList<>();
        node.addAll(bookList);
        node.addAll(wordsList);

        HashMap<String, Object> data = new HashMap<>();
        data.put("node", node);
        data.put("edges", edgeList);

        return new Result(200, "success", data);
    }


    @GetMapping("/api/subjectData1")
    @ResponseBody
    public Result findSubjectData1(){
        //存储最后返回的结果
        List<String> bookNode = new ArrayList<>();
        List<String> wordNode = new ArrayList<>();

        //选取一部分结果展示
        List<SubjectBook> bookList = subjectBookMapper.selectList(null);
        //随机打乱
//        shuffle(bookList);

        List<SubjectBook> batchBookList = bookList.subList(0, 30);
        //需要查询的书本,并对这些书本重新按照顺序编号
        int index = 0;
        HashMap<Integer, Integer> bookMap = new HashMap<>();
        //作为条件，查询bookWord
        List<Integer> bookId = new ArrayList<>();
        for(SubjectBook book: batchBookList){
            bookNode.add(book.getBookName());
            bookId.add(book.getBookId());
            bookMap.put(book.getBookId(), index);
            index++;
        }

        //查询这些书本对应的bookWord对象
        QueryWrapper<SubjectBookWord> qw = new QueryWrapper<>();
        qw.in("b_id", bookId);
        List<SubjectBookWord> bookWordsList = subjectBookWordMapper.selectList(qw);

        List<List<Integer>> edges = new ArrayList<>();
        //保存涉及到的word的wordId
        List<Integer> wordList = new ArrayList<>();

        //把涉及到的word查询出来，并重新编号
        HashMap<Integer, Integer> wordMap = new HashMap<>();
        for(SubjectBookWord bookWord: bookWordsList){
            if (!wordMap.containsKey(bookWord.getWordId())){
                wordList.add(bookWord.getWordId());
                wordMap.put(bookWord.getWordId(), index);
                index++;
            }
            //保存边集
            List<Integer> temp = new ArrayList<>();
            temp.add(bookMap.get(bookWord.getBookId()));
            temp.add(wordMap.get(bookWord.getWordId()));
            edges.add(temp);
        }

        //查询对应的wordName
        QueryWrapper<SubjectWord> wrapper = new QueryWrapper<>();
        wrapper.in("w_id", wordList);
        List<SubjectWord> wordNamesList = subjectWordMapper.selectList(wrapper);

        for(SubjectWord word: wordNamesList){
            wordNode.add(word.getWordName());
        }

        List<Object> allNode = new ArrayList<>();
        allNode.addAll(bookNode);
        allNode.addAll(wordNode);

        HashMap<String, Object> data = new HashMap<>();
        data.put("node", allNode);
        data.put("edges", edges);

        return new Result(200, "success", data);


    }

    // 打乱列表实现方法1
    public <T> void shuffle(List<T> list) {
        int size = list.size();
        Random random = new Random();

        for(int i = 0; i < size; i++) {
            // 获取随机位置
            int randomPos = random.nextInt(size);

            // 当前元素与随机元素交换
            T temp = list.get(i);
            list.set(i, list.get(randomPos));
            list.set(randomPos, temp);
        }
    }

//    根据书名查询主题词
    @GetMapping("/api/searchTopicByBook/{bookName}")
    @ResponseBody
    public Result searchTopicByBook(@PathVariable("bookName") String bookName){

        String name = URLDecoder.decode(bookName);

        //查询书名对应的书对象
        QueryWrapper<SubjectBook> wrapper = new QueryWrapper<>();
        wrapper.eq("b_name", name);

        List<SubjectBook> bookList = subjectBookMapper.selectList(wrapper);

        if(bookList.size()==0){
            return new Result(200, "book not exsit", null);
        }

        SubjectBook book = bookList.get(0);

        //根据该对象的id找到其主题词
        QueryWrapper<SubjectBookWord> qw = new QueryWrapper<>();
        qw.eq("b_id", book.getBookId());
        List<SubjectBookWord> bookwords = subjectBookWordMapper.selectList(qw);

        int wordIndex = 1;

        //找到所有主题词的名称，并重新编号，保存边集
        List<Integer> wordIds = new ArrayList<>();
        for(SubjectBookWord bookWord: bookwords){
            wordIds.add(bookWord.getWordId());
        }
        QueryWrapper<SubjectWord> qw1 = new QueryWrapper<>();
        qw1.in("w_id", wordIds);
        List<SubjectWord> subjectWords = subjectWordMapper.selectList(qw1);

        List<String> wordNames = new ArrayList<>();
        for(SubjectWord word: subjectWords){
            wordNames.add(word.getWordName());
            wordIndex++;
        }

        List<String> node = new ArrayList<>();
        node.add(name);
        node.addAll(wordNames);

        List<List<Integer>> edges = new ArrayList<>();
        for(int i=1; i<wordIndex; i++){
            List<Integer> temp = new ArrayList<>();
            temp.add(0);
            temp.add(i);
            edges.add(temp);
        }

        HashMap<String, Object> data = new HashMap<>();
        data.put("node", node);
        data.put("edges", edges);

        return new Result(200, "success", data);

    }

    //    根据主题词查询书本
    @GetMapping("/api/searchBookByTopic/{wordName}")
    @ResponseBody
    public Result searchBookByTopic(@PathVariable("wordName") String wordName){

        String name = URLDecoder.decode(wordName);

        //查询主题名对应的主题对象
        QueryWrapper<SubjectWord> wrapper = new QueryWrapper<>();
        wrapper.eq("w_name", name);

        List<SubjectWord> wordList = subjectWordMapper.selectList(wrapper);

        if(wordList.size()==0){
            return new Result(200, "word not exsit", null);
        }

        SubjectWord word = wordList.get(0);

        //根据该对象的id找到其对应的bookwords对象
        QueryWrapper<SubjectBookWord> qw = new QueryWrapper<>();
        qw.eq("w_id", word.getWordId());
        List<SubjectBookWord> bookwords = subjectBookWordMapper.selectList(qw);

        int bookIndex = 1;

        //找到所有书本的名称，并重新编号，保存边集
        List<Integer> bookIds = new ArrayList<>();
        for(SubjectBookWord bookWord: bookwords){
            bookIds.add(bookWord.getBookId());
        }
        QueryWrapper<SubjectBook> qw1 = new QueryWrapper<>();
        qw1.in("b_id", bookIds);
        List<SubjectBook> subjectBooks = subjectBookMapper.selectList(qw1);

        if (subjectBooks.size()>=50){
            subjectBooks = subjectBooks.subList(0, 50);
        }

        List<String> bookNames = new ArrayList<>();
        for(SubjectBook book: subjectBooks){
            bookNames.add(book.getBookName());
            bookIndex++;
        }

        List<String> node = new ArrayList<>();
        node.add(name);
        node.addAll(bookNames);

        List<List<Integer>> edges = new ArrayList<>();
        for(int i=1; i<bookIndex; i++){
            List<Integer> temp = new ArrayList<>();
            temp.add(i);
            temp.add(0);
            edges.add(temp);
        }

        HashMap<String, Object> data = new HashMap<>();
        data.put("node", node);
        data.put("edges", edges);

        return new Result(200, "success", data);

    }

    @GetMapping("/api/subjectSearchReview")
    @ResponseBody
    public Result subjectSearchReview(){
        System.out.println("开始查询");
        //查询所有数据，以二级分类的形式返回
        List<SubjectVO> data = new ArrayList<>();

        //先查询所有的书，作为一级分类
        List<SubjectBook> bookList = subjectBookMapper.selectList(null);
        System.out.println("一级分类查询完毕");


        for(SubjectBook book: bookList){
            String bookId = "book_" + book.getBookId();
            SubjectVO subjectVO = new SubjectVO(book.getBookId(), book.getBookName(), bookId);
            List<SubVO> child = new ArrayList<>();

            //查出该书对应的主题词
            QueryWrapper<SubjectBookWord> wrapper = new QueryWrapper<>();
            wrapper.eq("b_id", book.getBookId());
            List<SubjectBookWord> bookWords = subjectBookWordMapper.selectList(wrapper);

            //主题词的id
            List<Integer> wordIds = new ArrayList<>();
            for(SubjectBookWord bookWord: bookWords){
                wordIds.add(bookWord.getWordId());
            }

            //当前文本有主题词
            if (wordIds.size()>0){
                //主题词对应的对象
                QueryWrapper<SubjectWord> qw = new QueryWrapper<>();
                qw.in("w_id", wordIds);
                List<SubjectWord> words = subjectWordMapper.selectList(qw);

                for(SubjectWord word: words){
                    String wordId = "word_" + word.getWordId();
                    SubVO subVO = new SubVO(word.getWordId(), word.getWordName(), wordId);
                    child.add(subVO);
                }
            }
            subjectVO.setChildren(child);
            data.add(subjectVO);

        }
        System.out.println("二级分类查询完毕");

        data = data.subList(0, 50);

        return new Result(200, "success", data);
    }

    @GetMapping("/api/subjectDeleteBook/{typeId}")
    @ResponseBody
    public Result subjectDeleteBook(@PathVariable String typeId){

        String type = typeId.split("_")[0];
            //删除书
        int bookId = Integer.parseInt(typeId.split("_")[1]);
        QueryWrapper<SubjectBook> wrapper = new QueryWrapper<>();
        wrapper.eq("b_id", bookId);
        subjectBookMapper.delete(wrapper);

        System.out.println("书本逻辑删除成功");

        return new Result(200, "success", null);
    }

    @GetMapping("/api/subjectDeleteBookWord/{idParam}")
    @ResponseBody
    public Result subjectDeleteBookWord(@PathVariable String idParam){

        int bookId = Integer.parseInt(idParam.split("mm")[0].split("_")[1]);
        int wordId = Integer.parseInt(idParam.split("mm")[1].split("_")[1]);

        QueryWrapper<SubjectBookWord> wrapper = new QueryWrapper<>();
        wrapper.eq("w_id", wordId).eq("b_id", bookId);
        subjectBookWordMapper.delete(wrapper);

        System.out.println("书-主题逻辑删除成功");

        return new Result(200, "success", null);
    }


    @GetMapping("/api/subjectTotal")
    @ResponseBody
    public Result subjectTotal(){
        //获取一共有多少条书本记录
        Integer total = subjectBookMapper.selectCount(null);
        BookTotalVo data = new BookTotalVo(total);
        return new Result(200, "success", data);
    }


    @GetMapping("/api/subjectSearchPageReview")
    @ResponseBody
    public Result subjectSearchPageReview(@ModelAttribute SubjectPageDTO subjectPageDTO){

        List<SubjectVO> data = new ArrayList<>();

        Page<SubjectBook> page = new Page<>();
        page.setCurrent(subjectPageDTO.getCurrentPage());
        page.setSize(subjectPageDTO.getNumPerPage());

        List<SubjectBook> bookList = subjectBookMapper.selectPage(page, null).getRecords();
        for (SubjectBook book: bookList){
            String bookId = "book_" + book.getBookId();
            SubjectVO subjectVO = new SubjectVO(book.getBookId(), book.getBookName(), bookId);
            List<SubVO> child = new ArrayList<>();

            //查出该书对应的主题词
            QueryWrapper<SubjectBookWord> wrapper = new QueryWrapper<>();
            wrapper.eq("b_id", book.getBookId());
            List<SubjectBookWord> bookWords = subjectBookWordMapper.selectList(wrapper);

            //主题词的id
            List<Integer> wordIds = new ArrayList<>();
            for(SubjectBookWord bookWord: bookWords){
                wordIds.add(bookWord.getWordId());
            }

            //当前文本有主题词
            if (wordIds.size()>0){
                //主题词对应的对象
                QueryWrapper<SubjectWord> qw = new QueryWrapper<>();
                qw.in("w_id", wordIds);
                List<SubjectWord> words = subjectWordMapper.selectList(qw);

                for(SubjectWord word: words){
                    String wordId = "word_" + word.getWordId();
                    SubVO subVO = new SubVO(word.getWordId(), word.getWordName(), wordId);
                    child.add(subVO);
                }
            }
            subjectVO.setChildren(child);
            data.add(subjectVO);
        }



        return new Result(200, "success", data);
    }

}
